package com.ccx.myinterpreter;

import java.util.List;

import com.ccx.myinterpreter.Stmt.FunDecl;

public class LoxFun implements Callable {

    private Stmt.FunDecl funDecl;
    private Envirement env;
    private boolean isInitlizer;

    public LoxFun(FunDecl funDecl, Envirement env) {
        this.funDecl = funDecl;
        this.env = env;
        this.isInitlizer = false;
    }

    public LoxFun(FunDecl funDecl, Envirement env, boolean isInitlizer) {
        this.funDecl = funDecl;
        this.env = env;
        this.isInitlizer = isInitlizer;
    }

    public LoxFun bindThis(LoxInstance instance) {
        Envirement newEnv = new Envirement(env);
        newEnv.declaration("this", instance);
        return new LoxFun(funDecl, newEnv);
    }

    public Stmt.FunDecl getFunDecl() {
        return funDecl;
    }

    public void setFunDecl(Stmt.FunDecl funDecl) {
        this.funDecl = funDecl;
    }

    public Envirement getEnv() {
        return env;
    }

    public void setEnv(Envirement env) {
        this.env = env;
    }

    @Override
    public Object call(Interpreter interpreter, List<Object> args) {
        Envirement newEnv = new Envirement(this.env);
        for (int i = 0; i < args.size(); i++) {
            newEnv.declaration(this.funDecl.params.get(i).getLexeme(), args.get(i));
        }
        try {
            interpreter.executeBlock(this.funDecl.body, newEnv);
        } catch (ReturnException e) {
            if(!isInitlizer)
                return e.getValue();
        }
        if(isInitlizer)
            return this.env.getAt("this", 0);
        return null;
    }

    public int arity() {
        return funDecl.params.size();
    }
    
}
